﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace Scan
{
    public class ListViewEx : ListView
    {
        /// <summary>
        /// The original parent of this control.
        /// </summary>
        Control prevParent = null;


        public ListViewEx()
        {
            InitializeComponent();
        }

        protected override void  OnParentChanged(EventArgs e)
        {
            if (this.Site == null || !this.Site.DesignMode)
            {
                if (this.prevParent != null)
                {
                    WndProcHooker.UnhookWndProc(prevParent, Win32.WM_NOTIFY);
                }
                // update the previous parent
                prevParent = this.Parent;

                // hook up the new parent
                if (this.Parent != null)
                {
                    WndProcHooker.HookWndProc(this.Parent, new WndProcHooker.WndProcCallback(this.WM_Notify_Handler), Win32.WM_NOTIFY);
                }
            }

            base.OnParentChanged(e);
        }


        /// <summary>
        /// Occurs when the user clicks a TreeNode with the mouse.
        /// </summary>
        public event ListViewItemMouseClickEventHandler ItemMouseClick;

        /// <summary>
        /// Occurs when the mouse pointer is over the control and a mouse button is clicked. 
        /// </summary>
        /// <param name="e">Provides data for the NodeMouseClick event.</param>
        protected void OnItemMouseClick(ListViewItemMouseClickEventArgs e)
        {
            if (ItemMouseClick != null)
                ItemMouseClick(this, e);
        }



        int WM_Notify_Handler(IntPtr hwnd, uint msg, uint wParam, int lParam, ref bool handled)
        {
            Win32.NMHDR nmHdr = new Win32.NMHDR();
            System.Runtime.InteropServices.Marshal.PtrToStructure((IntPtr)lParam, nmHdr);
            switch (nmHdr.code)
            {
                case Win32.NM_RCLICK:
                case Win32.NM_CLICK:
                    // get the cursor coordinates on the client
                    Point msgPos = Win32.LParamToPoint((int)Win32.GetMessagePos());
                    msgPos = this.PointToClient(msgPos);

                    // check to see if the click was on an item
                    Win32.LVHITTESTINFO hti = new Win32.LVHITTESTINFO();
                    hti.pt.X = msgPos.X;
                    hti.pt.Y = msgPos.Y;
                    int hitem = Win32.SendMessage(this.Handle, Win32.LVM_SUBITEMHITTEST, 0, ref hti);

                    uint htMask = Win32.LVHT_ONITEM;
                    //uint htMask = (
                    //    Win32.LVHT_ABOVE |
                    //    Win32.LVHT_BELOW |
                    //    Win32.LVHT_NOWHERE |
                    //    Win32.LVHT_ONITEMICON |
                    //    Win32.LVHT_ONITEMLABEL |
                    //    Win32.LVHT_ONITEMSTATEICON |
                    //    Win32.LVHT_TOLEFT |
                    //    Win32.LVHT_TORIGHT);

                    if ((hti.flags & htMask) != 0)
                    {
                        bool leftButton = (nmHdr.code == Win32.NM_CLICK);
                        
                        RaiseItemMouseClickEvent(hti.iItem, hti.iSubItem, leftButton ? MouseButtons.Left : MouseButtons.Right, msgPos);
                        return 0;
                    }
                    break;

                default:
                    break;
            }
            return 0;
        }

        void RaiseItemMouseClickEvent(int iItem, int iSubItem, MouseButtons button, Point coords)
        {
            ListViewItemMouseClickEventArgs e = new ListViewItemMouseClickEventArgs(
                this.Items[iItem],
                iSubItem,
                button,
                1, coords.X, coords.Y);

            OnItemMouseClick(e);
        }

        /// <summary> 
        /// 必需的设计器变量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary> 
        /// 清理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源，为 true；否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region 组件设计器生成的代码

        /// <summary> 
        /// 设计器支持所需的方法 - 不要
        /// 使用代码编辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            components = new System.ComponentModel.Container();
        }

        #endregion
    }
}


namespace System.Windows.Forms
{
    /// <summary>
    /// Represents the method that will handle the NodeMouseClick event of a TreeView
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">A ListViewItemMouseClickEventArgs that contains the event data.</param>
    public delegate void ListViewItemMouseClickEventHandler(object sender, ListViewItemMouseClickEventArgs e);

    /// <summary>
    /// Provides data for the System.Windows.Forms.TreeView.NodeMouseClick event
    /// </summary>
    public class ListViewItemMouseClickEventArgs : MouseEventArgs
    {
        /// <summary>
        /// Initializes a new instance of the ListViewItemMouseClickEventArgs class.
        /// </summary>
        /// <param name="node">The node that was clicked</param>
        /// <param name="button">One of the System.Windows.Forms.MouseButtons members</param>
        /// <param name="clicks">The number of clicks that occurred</param>
        /// <param name="x">The x-coordinate where the click occurred</param>
        /// <param name="y">The y-coordinate where the click occurred</param>
        public ListViewItemMouseClickEventArgs(ListViewItem item, int subItemIndex, MouseButtons button, int clicks, int x, int y) :
            base(button, clicks, x, y, 0)
        {
            this.itemValue = item;
            this.subItemIndex = subItemIndex;
        }

        /// <summary>
        /// Gets the node that was clicked.
        /// </summary>
        public ListViewItem Item
        {
            get { return itemValue; }
            set { itemValue = value; }
        }
        ListViewItem itemValue;

        public int SubItemIndex
        {
            get { return subItemIndex; }
            set { subItemIndex = value; }
        }
        int subItemIndex;

        public override string ToString()
        {
            return string.Format(
                "ListViewItemMouseClickEventArgs\r\n\tNode: {0}\r\n\tButton: {1}\r\n\tX: {2}\r\n\tY: {3}",
                itemValue.Text, Button.ToString(), X, Y);
        }
    }
}

